package br.ufrj.neg.model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import br.ufrj.neg.bean.Idioma;
import br.ufrj.neg.bean.TraducaoBean;

public class TraducaoModel {
	
	/**
	 * Checa se o elemento realmente existe na tabela original
	 * Deve gerar uma consulta do tipo 
	 * SELECT COUNT(*) nome_tabela_original WHERE pk_tabela_original=id_elemento
	 * @param bean
	 * @param conn
	 * @return
	 */
	public static Boolean elementoExiste(TraducaoBean bean) {
		if (bean != null) {
			PreparedStatement ps = null;
			ResultSet rs = null;
			Connection conn = ServiceLocator.getConnection();
			try{			
				String sql;
				//Pegando o nome da tabela original
				sql = "SELECT taid_ds_nome AS nome_tabela "+
				"FROM tabela_idiomada "+
				"WHERE taid_cd_id = "+ bean.getIdTabela();				  	
				ps = conn.prepareStatement(sql);
				rs = ps.executeQuery();
				String nomeTabela="";
				while (rs.next()) {
					nomeTabela = rs.getString("nome_tabela");
				}


				//Pegando o nome da pk da tabela original
				sql = "SELECT taid_ds_nome_id AS nome_campo_id " +
				"FROM tabela_idiomada "+
				"WHERE taid_cd_id = "+bean.getIdTabela();				  
				ps = conn.prepareStatement(sql);
				rs = ps.executeQuery();
				String nomeCampoID="";
				while (rs.next()) {
					nomeCampoID = rs.getString("nome_campo_id");
				}

				//Verificando se ha elementos na tabela original com o idTabela
				sql = "SELECT COUNT(*) AS cont_elems " +
				"FROM " + nomeTabela + " " +
				"WHERE " + nomeCampoID + " = " + bean.getId();

				ps = conn.prepareStatement(sql);
				rs = ps.executeQuery();
				int contElems=-1;
				while (rs.next()) {
					contElems = rs.getInt("cont_elems");
				}
				return (contElems>0?true:false);
			}

			catch(Exception e){
				System.out.println(e);
				return false;
			}finally{
				try{rs.close();}catch(Exception e){System.out.println(e);}
				try{ps.close();}catch(Exception e){System.out.println(e);}			
			}
		}		
		try {
			throw new Exception("O elemento nao existe na tabela original!");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * @param bean
	 * @return Um HashMap com o conjunto de campos idiomaveis de um bean. Com os seus respectivos ids, na tabela Campo_Idiomado.
	 */
	public static HashMap<String,Integer> getIdsCampoIdiomado(TraducaoBean bean) {			
		if (bean != null) {
			HashMap<String,Integer> ids = new HashMap<String,Integer>();
			
			PreparedStatement ps = null;
			ResultSet rs = null;	
			Connection conn = ServiceLocator.getConnection();
			try{												
				String where = "";
		
				for( String nomeCampo:bean.getDicionario().keySet() ){
					where += "caid_ds_nome = '" + nomeCampo + "' OR " ;					
				}
				where = where.substring(0, where.lastIndexOf("OR") );
				
				String sql = "SELECT caid_ds_nome,caid_cd_id FROM campo_idiomado WHERE taid_cd_id = ? AND (" + where + ")";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, bean.getIdTabela());				
							
				rs = ps.executeQuery();
				
				int idCampoIdiomado=-1;
				String nomeCampo = "";
				while (rs.next()) {
					nomeCampo = rs.getString("caid_ds_nome");
					idCampoIdiomado = rs.getInt("caid_cd_id");
					ids.put(nomeCampo, idCampoIdiomado);
				}
				
				if (ids.size() > 0) return ids;
				else throw new Exception("Campo idiomado invalido!");
			}catch(Exception e){
				System.out.println(e);
				return null;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}				
			}			
		}
		return null;		
	}
	
	/** 
	 * Este metodo nao deve ser mais usado. Ao inves dele, use Idioma.instancias[idIdioma]
	 * @param idIdioma
	 * @param conn
	 * @return Uma instancia do idioma que tem a sigla do registro referente a idIdioma	 * 
	 */
	@Deprecated
	public static Idioma getIdioma(int idIdioma) {		
		if (idIdioma > 0 ) {			
			PreparedStatement ps = null;
			ResultSet rs = null;		
			Connection conn = ServiceLocator.getConnection();
			try{								
				String sql = "SELECT idio_ds_sigla FROM idioma WHERE idio_cd_id=?";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, idIdioma);				
				rs = ps.executeQuery();
				
				String sigla_idioma=null;
				while (rs.next()) {
					sigla_idioma = rs.getString("idio_ds_sigla");
				}
				if (sigla_idioma != null) return new Idioma(sigla_idioma);
				else throw new Exception();
			}catch(Exception e){
				System.out.println(e);
				return null;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}				
			}			
		}
		return null;	
	}	
	
	/**
	 * Insere somente a traducao do idioma passado por parametro
	 * @param bean
	 * @param idioma
	 * @return 1 se sucesso; < 0 se excecao eh lancada.
	 */
	public static int insereUmIdioma(TraducaoBean bean, Idioma idioma){
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		if (elementoExiste(bean)) {
			try{
				String sql;				
				
				int idIdioma = idioma.getIdIdioma();//TraducaoConstantes.getIdIdioma(idioma);
							
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
				
				int idElemento = bean.getId();
				
				for(String campo:idsCampoIdiomado.keySet()){
					int idCampoIdiomado = idsCampoIdiomado.get(campo);
					
					sql = "INSERT INTO traducao(" +
					"idio_cd_id,caid_cd_id,trad_cd_elem_id,trad_ds_texto) " +
					"VALUES(?,?,?,?)";					
					
					ps=conn.prepareStatement(sql);
					ps.setInt(1, idIdioma);
					ps.setInt(2, idCampoIdiomado);
					ps.setInt(3, idElemento);
					ps.setString(4, bean.getDicionario().get(campo).get(idioma));
					
					ps.executeUpdate();
				}
				
				conn.commit();

				return 1;
			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}
		}	
		return -2;
	}
	
	/**
	 * Insere a traducao de todos os idiomas que estao no bean	
	 * @param bean
	 * @return 1 se sucesso; < 0 se excecao eh lancada. 
	 */
	public static int insere(TraducaoBean bean){

		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		if (elementoExiste(bean)) {
			try{
				String sql;	
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
				
				int idElemento = bean.getId();

				//Para cada campo idiomado...
				for(String campo:idsCampoIdiomado.keySet()){					
					
					//Para cada idioma, faz uma insercao no banco...
					for (Idioma idioma :  bean.getDicionario().get(campo).keySet() ) {

						int idIdioma = idioma.getIdIdioma();//TraducaoConstantes.getIdIdioma(idioma);			
						
						sql = "INSERT INTO traducao(" +
						"idio_cd_id,caid_cd_id,trad_cd_elem_id,trad_ds_texto) " +
						"VALUES(?,?,?,?)";					

						ps=conn.prepareStatement(sql);
						ps.setInt(1, idIdioma);
						ps.setInt(2, idsCampoIdiomado.get(campo));
						ps.setInt(3, idElemento);
						ps.setString(4, bean.getDicionario().get(campo).get(idioma));					

						ps.executeUpdate();
						
					}	
					
				}
				
				conn.commit();
				
				return 1;

			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}			
		}
		return -2;		
	}
	
	/**	 
	 * Atualiza somente a traducao do idioma passado por parametro	 
	 * @param bean
	 * @param idioma
	 * @return
	 */
	public static int atualizaUmIdioma(TraducaoBean bean, Idioma idioma){
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		if (elementoExiste(bean)) {
			try{
				String sql;				
				
				int idIdioma = idioma.getIdIdioma();//TraducaoConstantes.getIdIdioma(idioma);					
				
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
								
				int idElemento = bean.getId();
				
				//Para cada campo idiomado...
				for(String campo:idsCampoIdiomado.keySet()){				
					sql = "UPDATE traducao SET " +
							  "idio_cd_id=?,"+
							  "caid_cd_id=?,"+
							  "trad_cd_elem_id=?,"+
							  "trad_ds_texto=? "+
						  "WHERE (" +
						 	  "idio_cd_id=? AND "+
						 	  "caid_cd_id=? AND "+
						 	  "trad_cd_elem_id=?"+						  
					 	  ");";				
	
					ps=conn.prepareStatement(sql);
					ps.setInt(1, idIdioma);
					ps.setInt(2, idsCampoIdiomado.get(campo));
					ps.setInt(3, idElemento);
					ps.setString(4,  bean.getDicionario().get(campo).get(idioma));
					ps.setInt(5, idIdioma);
					ps.setInt(6, idsCampoIdiomado.get(campo));
					ps.setInt(7, idElemento);
					ps.executeUpdate();	
				}				
			
				conn.commit();
				
				return 1;
			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}
		}	
		return -2;
	}
	
	/**	 
	 * Atualiza todas as traducoes dos idiomas do elemento que esta no bean	 
	 * @param bean
	 * @return
	 */
	public static int atualiza(TraducaoBean bean){
		
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		
		if (elementoExiste(bean)) {
			try {
				String sql;	
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
				
				int idElemento = bean.getId();
	
				TraducaoBean traducao = getTraducoesElemento(bean);
								
				//Para cada campo idiomado...
				for(String campo:idsCampoIdiomado.keySet()) {
					
					HashMap<Idioma,String> inseridos = traducao.getDicionario().get(campo);
					
					//Para cada idioma, faz uma insercao no banco...
					for (Idioma idioma : bean.getDicionario().get(campo).keySet() ) {
						
						int idIdioma = idioma.getIdIdioma();//TraducaoConstantes.getIdIdioma(idioma);						
						
						if( inseridos.containsKey(idioma) ){	
							sql = "UPDATE traducao SET " +
									  "idio_cd_id=?,"+
									  "caid_cd_id=?,"+
									  "trad_cd_elem_id=?,"+
									  "trad_ds_texto=? "+
								  "WHERE (" +
									 	  "idio_cd_id=? AND "+
									 	  "caid_cd_id=? AND "+
									 	  "trad_cd_elem_id=?"+						  
									 	  ");";				
							
							ps=conn.prepareStatement(sql);
							ps.setInt(1, idIdioma);
							ps.setInt(2, idsCampoIdiomado.get(campo));
							ps.setInt(3, idElemento);
							ps.setString(4, bean.getDicionario().get(campo).get(idioma));
							ps.setInt(5, idIdioma);
							ps.setInt(6, idsCampoIdiomado.get(campo));
							ps.setInt(7, idElemento);

							ps.executeUpdate();
						}
						else{
							sql = "INSERT INTO traducao(" +
							"idio_cd_id,caid_cd_id,trad_cd_elem_id,trad_ds_texto) " +
							"VALUES(?,?,?,?)";
							
							
							ps=conn.prepareStatement(sql);
							ps.setInt(1, idIdioma);
							ps.setInt(2, idsCampoIdiomado.get(campo));
							ps.setInt(3, idElemento);
							ps.setString(4, bean.getDicionario().get(campo).get(idioma));
							
							ps.executeUpdate();
						}
						
					}
					
				}									
				conn.commit();							
				
				return 1;		
			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}			
		}		
		return -2;	
	}
	
	/**
	 * Remove somente a traducao do idioma passado por parametro
	 * @param bean
	 * @param idioma
	 */
	public static int removeUmIdioma(TraducaoBean bean, Idioma idioma){
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		if (elementoExiste(bean)) {
			try{
				String sql;				
				
				int idIdioma = idioma.getIdIdioma();//TraducaoConstantes.getIdIdioma(idioma);								
				
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
				
				int idElemento = bean.getId();
				
				for(String campo:idsCampoIdiomado.keySet()) {	
					sql = "DELETE FROM traducao WHERE idio_cd_id=? AND caid_cd_id=? AND trad_cd_elem_id=?;";

					ps=conn.prepareStatement(sql);
					ps.setInt(1, idIdioma);
					ps.setInt(2, idsCampoIdiomado.get(campo));
					ps.setInt(3, idElemento);
					ps.executeUpdate();
				}
				conn.commit();				
				return 1;
			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{				
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}
		}	
		return -2;
	}
	
	/**
	 * Remove todas as traducoes dos idiomas que estao no bean
	 * @param bean
	 */
	public static int remove(TraducaoBean bean){
		
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		if (elementoExiste(bean)) {
			try{
				String sql;	
				HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
				if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
				
				int idElemento = bean.getId();

				for(String campo:idsCampoIdiomado.keySet()) {	
				
					sql = "DELETE FROM traducao WHERE caid_cd_id=? AND trad_cd_elem_id=?;";					
					ps=conn.prepareStatement(sql);
					ps.setInt(1, idsCampoIdiomado.get(campo));
					ps.setInt(2, idElemento);					

					ps.executeUpdate();
				}
				
				conn.commit();					
					
				return 1;

			}catch(Exception e){
				System.out.println(e);
				return -1;
			}finally{
				try{ps.close();}catch(Exception e){System.out.println(e);}
				try{conn.close();}catch(Exception e){System.out.println(e);}
			}			
		}
		return -2;
	}	
	
	/**
	 * @param bean O bean que deve ter o id do elemento a ser buscado na consulta
	 * @return Um bean com todas as traducoes do elemento idElemento da tabela idTabela
	 */
	public static TraducaoBean getTraducoesElemento(TraducaoBean bean) {
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
		try{				
			TraducaoBean tradBean = bean.getNewInstance();
			HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
			if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
			
			for(String campo:idsCampoIdiomado.keySet()) {	
							
				String sql = "SELECT * "+
							"FROM traducao "+
							"WHERE caid_cd_id=? AND trad_cd_elem_id=? "+
							"ORDER BY idio_cd_id";
				
				ps = conn.prepareStatement(sql);
				ps.setInt(1,idsCampoIdiomado.get(campo));
				ps.setInt(2,bean.getId());
				rs = ps.executeQuery();
				
				while (rs.next()){			
					String texto = rs.getString("trad_ds_texto");
					int idIdioma = rs.getInt("idio_cd_id");				
					Idioma idioma = Idioma.instancias[idIdioma]; //getIdioma(idIdioma);
					if (idioma==null) throw new Exception("IdiomaException: " + idsCampoIdiomado);
					tradBean.setTraducao(idioma, campo, texto);				
				}				
			}	
			return tradBean;
		}catch(Exception e){
			System.out.println(e);
			return null;
		}finally{				
			try{ps.close();}catch(Exception e){System.out.println(e);}
			try{conn.close();}catch(Exception e){System.out.println(e);}				
		}		
	}
	
	/**
	 * @param bean O bean da classe(tabela) sobre a qual o metodo deve retornar as traducoes  
	 * @return Uma Collection com todas as traducoes referentes a tabela do bean
	 */
	public static Collection<TraducaoBean> getTraducoes(TraducaoBean bean) {				
		Connection conn = ServiceLocator.getConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
		try{
			Collection<TraducaoBean> c = new ArrayList<TraducaoBean>();					
			String sql = "SELECT * FROM traducao WHERE caid_cd_id=? ORDER BY caid_cd_id, idio_cd_id";
			ps = conn.prepareStatement(sql);
			
			HashMap<String,Integer> idsCampoIdiomado = getIdsCampoIdiomado(bean);
			if (idsCampoIdiomado.size() < 0) throw new Exception("CampoIdiomadoException: " + idsCampoIdiomado);
			
			for(String campo:idsCampoIdiomado.keySet()) {
				
				ps.setInt(1,idsCampoIdiomado.get(campo));			
				rs = ps.executeQuery();		
				
				while (rs.next()){				
					TraducaoBean tradBean = bean.getNewInstance();
					String texto = rs.getString("trad_ds_texto");
					int idIdioma = rs.getInt("idio_cd_id");				
					Idioma idioma = Idioma.instancias[idIdioma];//getIdioma(idIdioma);			
					tradBean.setTraducao(idioma, campo, texto);
					c.add(tradBean);
				}
				
			}		
			return c;
		}catch(Exception e){
			System.out.println(e);
			return null;
		}finally{				
			try{ps.close();}catch(Exception e){System.out.println(e);}
			try{conn.close();}catch(Exception e){System.out.println(e);}				
		}
	}	

	
}
